import java.util.NoSuchElementException;

public class LinkedListRemove<E> {
    private Node<E> first;
    private int size;

    private static class Node<E> {
        E item;
        Node<E> next;

        Node(E item, Node<E> next) {
            this.item = item;
            this.next = next;
        }
    }

    /**
     * Adds an element to the end of the list.
     * @param element the element to add
     */
    public void add(E element) {
        if (first == null) {
            first = new Node<>(element, null);
        } else {
            Node<E> current = first;
            while (current.next != null) {
                current = current.next;
            }
            current.next = new Node<>(element, null);
        }
        size++;
    }

    /**
     * Returns the element at the specified position in the list.
     * @param index the index of the element to return
     * @return the element at the specified position
     * @throws IndexOutOfBoundsException if the index is out of range
     */
    public E get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
        Node<E> current = first;
        for (int i = 0; i < index; i++) {
            current = current.next;
        }
        return current.item;
    }

    /**
     * Returns the number of elements in the list.
     * @return the number of elements in the list
     */
    public int size() {
        return size;
    }

    /**
     * Removes the first occurrence of the specified element from this list.
     * @param o element to be removed
     * @return true if the list contained the specified element
     */
    public boolean remove(Object o) {
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Unlinks the specified node from the list.
     * @param node the node to unlink
     */
    private void unlink(Node<E> node) {
        if (node == first) {
            first = first.next;
        } else {
            Node<E> prev = first;
            while (prev.next != node) {
                prev = prev.next;
            }
            prev.next = node.next;
        }
        size--;
    }
}